package cn.ilikes.tools.nosql.jpa.persistences.contexts;

import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;

import javax.persistence.EntityTransaction;

import org.slf4j.Logger;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.JPASQLPersistenUnitEnv;
import cn.ilikes.tools.nosql.jpa.clients.AbClient;
import cn.ilikes.tools.nosql.jpa.graphs.Node;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;

public abstract class AbstractContext implements Context {

	private static Logger logger = Loggerfactory.instance(AbstractContext.class);

	private Stack<Operation<?>> qperationsStack = new Stack<Operation<?>>();

	private Map<Object, Node> cache = new ConcurrentHashMap<Object, Node>();

	private JPASQLPersistenUnitEnv persistenUnitEnv;

	private AbClient client;

	public AbstractContext(JPASQLPersistenUnitEnv hbasePersistenUnitEnv, AbClient clients) {
		super();
		this.persistenUnitEnv = hbasePersistenUnitEnv;
		this.client = clients;
		clients.setAbstractContext(this);
	}

	@Override
	public void init() {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.info(logger, "JPA SQL  context   init   ");
		client.init();

	}

	public Stack<Operation<?>> getQperationsStack() {
		return qperationsStack;
	}

	public EntityTransaction createEntityTransaction() {
		EntityTransaction entityTransaction = new JPAHBaseTransaction(this);
		return entityTransaction;
	}

	@Override
	public <V> Object operation(Operation<V> operation) {
		operation.init();
		Object value = operation.exec();
		qperationsStack.push(operation);
		return value;
	}

	@Override
	public void rollback() {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "AbstractContext  rollback");
		AbClient client = getClient();
		while (!qperationsStack.isEmpty()) {
			Operation<?> qperations = qperationsStack.pop();
			qperations.rollback();
		}
		client.rollback();
	}

	@Override
	public void commit() {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "AbstractContext  commit");
		AbClient client = getClient();
		client.commit();

	}

	@Override
	public void clear() {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "AbstractContext  clear");
		cache.clear();
	}

	public AbClient getClient() {
		return client;
	}

	@Override
	public void flush() {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "AbstractContext  flush");
		AbClient client = getClient();
		do {
			Operation<?> qperations = qperationsStack.pop();
			qperations.flush();
		} while (!qperationsStack.isEmpty());
		client.flush();

	}

	public void putCache(Object key, Node value) {
		String cache_key = value.getEntityMetaData().getEntityTableName() + "_" + key;
		cache.put(cache_key, value);
	}

	public Node getCache(Object key, EntityMetaData entityMetaData) {
		String cache_key = entityMetaData.getEntityTableName() + "_" + key;
		Node node = cache.get(cache_key);
		return node;

	}

	public JPASQLPersistenUnitEnv getPersistenUnitEnv() {
		return persistenUnitEnv;
	}

	public void close() {
		client.close();
		cache.clear();

	}

}
